package jou.cs.support.response;

import com.google.gson.Gson;
import jou.cs.support.ResponseRewrite;
import jou.cs.support.enums.ResponseCode;
import lombok.AllArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;

@AllArgsConstructor
@RestControllerAdvice(basePackages = {"jou.cs.controller"})
public class responseHandler implements ResponseBodyAdvice<Object> {

    protected final List<ResponseRewrite> handlers;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return handlers.size() != 0;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        AtomicReference<Object> data = new AtomicReference<>(R.fail());

        List<Integer> list;
        handlers.stream().filter(rewriter -> rewriter.support(body))
                .findFirst()
                .ifPresent(handler -> data.set(handler.parse(body)));

        return data.get();
    }

    @Component
    static class general implements ResponseRewrite {
        @Override
        public boolean support(Object body) {
            return Stream.of(Boolean.class, Character.class, Number.class, Collection.class, Map.class)
                    .anyMatch(clazz -> clazz.isInstance(body));
        }
    }

    @Component
    static class string implements ResponseRewrite {
        @Resource
        private Gson gson;

        @Override
        public boolean support(Object body) {
            return body instanceof String;
        }

        @Override
        public Object parse(Object body) {
            return gson.toJson(R.then(body));
        }
    }

    @Component
    static class responseCode implements ResponseRewrite {
        @Override
        public boolean support(Object body) {
            return body instanceof ResponseCode;
        }

        @Override
        public Object parse(Object body) {
            return R.fail((ResponseCode) body);
        }
    }

    @Component
    static class page implements ResponseRewrite {
        @Override
        public boolean support(Object body) {
            return body instanceof Page;
        }

        @Override
        public Object parse(Object body) {
            Page<?> page = (Page<?>) body;

            HashMap<String, Object> map = new HashMap<>();

            map.put("total", page.getTotalElements());
            map.put("content", page.getContent());
            map.put("next", page.hasNext());

            return R.then(map);
        }
    }

}
